#!/usr/bin/env python
from racecar.bayes import *
from racecar.data import BayesData, StateManager
from os import path

# Parse Orange formatted data, return BayesData. 
def parseOrangeData(file):
  # Does the file exist?
  if not path.isfile(file):
    raise Exception, "Data file does not exist.";
  
  # First pass - find dimensions of matrix.
  rows = int();
  cols = int();
  f = open(file);
  f.readline(); 
  for line in f:
    things = line.split('\t');
    things[-1] = things[-1].strip();
    size = len(things);
    if size > cols:
      cols = size;
      
    rows += 1;
  
  f.close();
  
  # Second pass - store data.
  data = BayesData(cols,rows);
  f = open(file);
  
  # Get header.
  header = [i.strip() for i in f.readline().split('\t')];
  for i in xrange(len(header)):
    data.setVariableName(i,header[i]);
    
  # Next line doesn't contain anything really useful.
  # We should make sure there are no continuous variables, though.
  doc = f.readline().split('\t');
  doc[-1] = doc[-1].strip();
  for i in doc:
    if i == "c" or i == "continuous":
      raise Exception, "Continuous variable found, cannot continue.";
  
  # Next line doesn't tell us much either other than the class variable.
  line3 = f.readline().split('\t');
  line3[-1] = line3[-1].strip();
  for i in xrange(len(line3)):
    if line3[i] == "class":
      data.setClassVar(i);
      break;
    
    if line3[i] == "ignore" or line3[i] == "i":
      print "Ignoring a variable is not supported yet - variable " + str(i) + " included..";
    
  # Now, store the data.
  currentRow = 0;
  for line in f:
    things = line.split('\t');
    things[-1] = things[-1].strip();
    for i in xrange(len(things)):
      data.setValue(i,currentRow,things[i]);
      
    currentRow += 1;
  
  # Return the object.
  return data;

# Parse a data file and return a BayesData object.
# File is a string representing the absolute path to the data file.
# The data file must be the same as expected by racecar.
# -- Tab delimited
# -- Rows are observations
# -- Columns are variables
# -- A header row naming each variable MUST exist!
# -- Named and numerical states are acceptable. 
def parseBayesData(file):
  # Does the file exist?
  if not path.isfile(file):
    raise Exception, "Data file does not exist.";
  
  # First pass - find dimensions of matrix.
  rows = int();
  cols = int();
  f = open(file);
  f.readline(); 
  for line in f:
    things = line.split('\t');
    things[-1] = things[-1].strip();
    size = len(things);
    if size > cols:
      cols = size;
      
    rows += 1;
  
  f.close();
  
  # Second pass - store data.
  data = BayesData(cols,rows);
  f = open(file);
  
  # Get header.
  header = [i.strip() for i in f.readline().split('\t')];
  for i in xrange(len(header)):
    data.setVariableName(i,header[i]);
    
  # Now, store the data.
  currentRow = 0;
  for line in f:
    things = line.split('\t');
    things[-1] = things[-1].strip();
    for i in xrange(len(things)):
      data.setValue(i,currentRow,things[i]);
      
    currentRow += 1;
  
  # Return the object.
  return data;

# Creates a posterior object from a .posterior.tab file,
# or an already opened file object. 
class PosteriorExtractor:
  # Constructor.
  def __init__(self,posterior=UniquePosterior()):
    self.posterior = posterior
  
  # Parse a posterior file. 
  def parse(self,filename):
    if not path.isfile(filename):
      raise Exception, "Couldn't find posterior file " + filename;
    
    f = open(filename);
    f.readline(); # kill header
    for line in f:
      elements = [i.strip() for i in line.split('\t')];
      self.posterior.update(elements[2],Network.fromString(elements[1]));
    
    f.close();
    
  # Parse an already opened file object (from popen, for example.)
  # This method can handle multiple concatenated results. 
  def parseFileObject(self,f):
    # Flag for parsing.
    doParse = False;
    
    # Parse the rest of the data. 
    for line in f:
      if not doParse:
        elements = [i.strip() for i in line.split('\t')];
        if elements[0] == "#" and elements[1] == "Network":
          doParse = True;
      else:
        if line == "\n":
          doParse = False;
        else:
          elements = [i.strip() for i in line.split('\t')];
          self.posterior.update(elements[2],Network.fromString(elements[1]));
    
    err = f.close();
    if err:
      raise RuntimeError,"File object " + str(f) + " had error " + str(err);
    
  # Get a reference to the latest posterior. 
  def getPosterior(self):
    return self.posterior;
            